package com.huanzhidadi.singleweb.pageinfo.util;

import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.ClassMapBuilder;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class BeanCopyUtil {

    // 映射工厂
    private static MapperFactory MAPPER_FACTORY = new DefaultMapperFactory.Builder().build();

    // 默认映射实例
    private static MapperFacade MAPPER_FACADE = MAPPER_FACTORY.getMapperFacade();

    // 空间换时间
    private static Map<String, MapperFacade> CACHE_MAPPER_FACADE_MAP = new ConcurrentHashMap<>();


    /**
     * 普通对象转换
     *
     * @param source
     * @param targetClass
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S, T> T copy(S source, Class<T> targetClass) {

        try {
            return MAPPER_FACADE.map(source, targetClass);
        } catch (Exception e) {
            throw new RuntimeException("类型转换异常", e);
        }
    }

    /**
     * 自定义普通对象转换
     *
     * @param source
     * @param targetClass
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S, T> T copy(S source, Class<T> targetClass, Map<String, String> mapperMap) {

        try {
            if (CollectionUtils.isEmpty(mapperMap)) {
                throw new RuntimeException("mapperMap 不能为空");
            }
            MapperFacade mapperFacade = getMapperFacade(source.getClass(), targetClass, mapperMap);
            return mapperFacade.map(source, targetClass);
        } catch (Exception e) {
            throw new RuntimeException("类型转换异常", e);
        }
    }

    /**
     * List类型转换
     *
     * @param sourceList
     * @param targetClass
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S, T> List<T> copyList(Iterable<S> sourceList, Class<T> targetClass) {

        try {
            return MAPPER_FACADE.mapAsList(sourceList, targetClass);
        } catch (Exception e) {
            throw new RuntimeException("类型转换异常", e);
        }
    }

    /**
     * 自定义List类型转换
     *
     * @param sourceList
     * @param sourceClass
     * @param targetClass
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S, T> List<T> copyList(Iterable<S> sourceList, Class<S> sourceClass, Class<T> targetClass, Map<String, String> mapperMap) {

        try {
            if (CollectionUtils.isEmpty(mapperMap)) {
                throw new RuntimeException("mapperMap 不能为空");
            }
            MapperFacade mapperFacade = getMapperFacade(sourceClass, targetClass, mapperMap);
            return mapperFacade.mapAsList(sourceList, targetClass);
        } catch (Exception e) {
            throw new RuntimeException("类型转换异常", e);
        }
    }

    /**
     * Set类型转换
     *
     * @param sourceSet
     * @param targetClass
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S, T> Set<T> copySet(Iterable<S> sourceSet, Class<T> targetClass) {

        try {
            return MAPPER_FACADE.mapAsSet(sourceSet, targetClass);
        } catch (Exception e) {
            throw new RuntimeException("类型转换异常", e);
        }
    }

    /**
     * 自定义Set类型转换
     *
     * @param sourceSet
     * @param sourceClass
     * @param targetClass
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S, T> Set<T> copySet(Iterable<S> sourceSet, Class<S> sourceClass, Class<T> targetClass, Map<String, String> mapperMap) {

        try {
            if (CollectionUtils.isEmpty(mapperMap)) {
                throw new RuntimeException("mapperMap 不能为空");
            }
            MapperFacade mapperFacade = getMapperFacade(sourceClass, targetClass, mapperMap);
            return mapperFacade.mapAsSet(sourceSet, targetClass);
        } catch (Exception e) {
            throw new RuntimeException("类型转换异常", e);
        }
    }

    /**
     * 获取自定义MapperFacade
     *
     * @param sourceClass
     * @param targetClass
     * @param mapperMap
     * @param <S>
     * @param <T>
     * @return
     */
    private static <S, T> MapperFacade getMapperFacade(Class<S> sourceClass, Class<T> targetClass, Map<String, String> mapperMap) {

        String flag = new StringBuilder().append(sourceClass.getName()).append("-").append(targetClass.getName()).toString();
        MapperFacade cacheMapperFacade = CACHE_MAPPER_FACADE_MAP.get(flag);
        if (ObjectUtils.isEmpty(cacheMapperFacade)) {
            // 构建MapperFacade
            ClassMapBuilder<S, T> classMapBuilder = MAPPER_FACTORY.classMap(sourceClass, targetClass);
            mapperMap.forEach(classMapBuilder::field);  // 字段映射
            classMapBuilder.byDefault().register(); // 注册
        }
        MapperFacade mapperFacade = MAPPER_FACTORY.getMapperFacade();
        CACHE_MAPPER_FACADE_MAP.put(flag, mapperFacade);
        return mapperFacade;
    }
}
